#ifndef DMCOMM_H
#define DMCOMM_H

#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) \
|| defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#define Q_DECL_EXPORT __declspec(dllexport)
#define Q_DECL_IMPORT __declspec(dllimport)
#else
#define Q_DECL_EXPORT __attribute__((visibility("default")))
#define Q_DECL_IMPORT __attribute__((visibility("default")))
#endif

#if defined(DMCOMM_LIBRARY)
#define DMCOMM_EXPORT Q_DECL_EXPORT
#else
#define DMCOMM_EXPORT Q_DECL_IMPORT
#endif

#include <mutex>
#include <atomic>
#include <cassert>
#include <vector>
#include <functional>
#include <memory>

// 设备类型枚举
enum class DevType
{
    Virtual,    // 虚拟设备
    HID,        // HID
    Serial,     // 串口
    Network     // 网络
};

// 错误代码
enum DmCommError
{
    NoError,
    OpenError,
    WriteError,
    ReadError
};

// 设备信息
struct DevInfo
{
    DevType type;       // 类型
    std::string path;   // 打开标识
    std::string id;     // ID
    std::string desc;   // 描述
    bool operator==(const DevInfo &info) const
    {
        if (this->type != info.type ||
            this->path != info.path ||
            this->id != info.id ||
            this->desc != info.desc)
            return false;
        return true;
    }
};

class DeviceInterface;
class DMCOMM_EXPORT DmComm
{
private:
    DmComm();
    ~DmComm();

    DmComm(const DmComm&) = delete;
    DmComm& operator=(const DmComm&) = delete;
    DmComm(DmComm&&) = delete;
    DmComm& operator=(DmComm&&) = delete;

    void initialize();
    void cleanup();

    static std::atomic<bool> s_initialized;
    mutable std::mutex m_mutex;
public:
    static DmComm& getInstance();
    static bool isInitialized();
public:

    /**
     * @brief 注册获取错误信息的方法
     * @note 创建设备前注册
     */
    void registerErrorHandler(std::function<void(const int &)> handler);

    /**
     * @brief 注册读取数据的方法
     * @note 创建设备前注册
     */
    void registerRecvHandler(std::function<void(const std::vector<uint8_t> &)> handler);

    /**
     * @brief 获取设备信息
     * @param contain 是否包含虚拟设备
     */
    std::vector<DevInfo> getDeviceInfo(bool contain = false) const;

    /**
     * @brief 打开设备
     * @param info 设备信息
     * @note 先通过getDeviceInfo方法获取设备信息，再打开指定设备
     */
    void open(const DevInfo &info);

    /**
     * @brief 设备打开状态
     */
    bool isOpen() const;

    /**
     * @brief 关闭设备
     * @note 删除设备
     */
    void close();

    /**
     * @brief 向设备写入数据
     * @param data 字节流
     * @param timeout 读取超时时间 ms
     * @note 应答模式，通过recv接收
     */
    void write(const std::vector<uint8_t> &data, const uint16_t &timeout = 20);

private:
    std::function<void(const int &)> error;
    std::function<void(const std::vector<uint8_t> &)> recv;
    std::unique_ptr<DeviceInterface> m_ptr;
    bool m_closing = false;
};


#endif // DMCOMM_H
